package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private Client client;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private DeviceMapper deviceMapper;

    @Override
    public void syncProductList() {
        //通过client客户端远程调用阿里云Iot,获取Product产品列表数据
        QueryProductListRequest request = new QueryProductListRequest();
        //设置请求参数
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        request.setCurrentPage(1);
        request.setPageSize(200);

        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        //判断是否调用成功
        if (response == null || !response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }

        //将获取到的数据，封装成ProductVo
        List<ProductVo> productVoList = response.getBody().getData().getList().getProductInfo().stream().map(info -> BeanUtil.toBean(info, ProductVo.class)).collect(Collectors.toList());
        // 存储到redis中
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, JSONUtil.toJsonStr(productVoList));
    }

    @Override
    public List<ProductVo> allProduct() {
        //从Redis中读取产品列表集合
        String productListStr = redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        if (StrUtil.isEmpty(productListStr)) {
            return new ArrayList<>();
        }
        return JSONUtil.toList(productListStr, ProductVo.class);
    }

    @Override
    public int registerDevice(DeviceDto deviceDto) {
        //1.判断当前设备是否重名
        int num = deviceMapper.countByName(deviceDto.getDeviceName());
        if (num > 0) {
            throw new BaseException(BasicEnum.DEVICE_NAME_EXIST);
        }
        //2.远程调用阿里云的IOT平台，注册设备
        RegisterDeviceRequest registerRequest = new RegisterDeviceRequest();
        /*封装请求参数
         * 设备对应的产品KEY
         * IOT实例的ID
         * */
        registerRequest.setProductKey(deviceDto.getProductKey());
        registerRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        registerRequest.setDeviceName(deviceDto.getDeviceName());
        registerRequest.setNickname(deviceDto.getNickname());
        RegisterDeviceResponse registerDeviceresponse;
        try {
            registerDeviceresponse = client.registerDevice(registerRequest);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        if (registerDeviceresponse == null || !registerDeviceresponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }
        //获取IOT颁发给该设备的唯一id
        deviceDto.setIotId(registerDeviceresponse.getBody().getData().getIotId());
        //3.查询当前设备对应的产品的产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        //封装参数
        queryProductRequest.setProductKey(deviceDto.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse = client.queryProduct(queryProductRequest);
        } catch (Exception e) {

            throw new RuntimeException(e);
        }
        if (queryProductResponse == null || !queryProductResponse.getBody().getSuccess()) {
            deleteDevice(deviceDto);
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //获取结果
        String productName = queryProductResponse.getBody().getData().getProductName();

        deviceDto.setProductName(productName);

        //4.位置类型:0 老人 1 位置 如果判断是0 需要设置设备的物理位置 physical_location_type -1
        if (deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            deviceDto.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //5.保存设备到数据库
        try {
            Device device = BeanUtil.copyProperties(deviceDto, Device.class);
            return deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //6.保存出错，则需要回退数据
            deleteDevice(deviceDto);
            throw new BaseException(BasicEnum.SYSYTEM_FAIL);
        }
    }

    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
        //开启分页
        PageHelper.startPage(devicePageQueryDto.getPageNum(), devicePageQueryDto.getPageSize());
        //查询数据
        Page<DeviceVo> page = deviceMapper.selectDeviceByConditions(devicePageQueryDto);
        return PageResponse.of(page, DeviceVo.class);
    }

    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {
        //封装数据
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        //查询IOT平台的数据
        QueryDeviceDetailResponse response;
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (response == null || !response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.getBody().getData();

        //查数据库对应的数据
        DeviceVo deviceVo = deviceMapper.selectByIotId(data.getIotId());
        //组装数据并返回
        BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().ignoreNullValue());

        return deviceVo;
    }

    @Override
    @Transactional
    public int updateDevice(DeviceDto deviceDto) {
        //根据id查询该设备是否存在
        Device deviceDB = deviceMapper.selectByPrimaryKey(deviceDto.getId());
        if (deviceDB == null) {
            throw new BaseException(BasicEnum.DEVICE_NOT_EXIST);
        }
        if (deviceDto.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())) {
            deviceDto.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        if (!StrUtil.equals(deviceDB.getDeviceName(), deviceDto.getDeviceName())) {
            BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
            request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> list = getBatchUpdateDeviceNicknameRequestDeviceNicknameInfos(deviceDto);
            request.setDeviceNicknameInfo(list);
            BatchUpdateDeviceNicknameResponse batchUpdateDeviceNicknameResponse;
            try {
                batchUpdateDeviceNicknameResponse = client.batchUpdateDeviceNickname(request);
            } catch (Exception e) {
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
            if (batchUpdateDeviceNicknameResponse == null || !batchUpdateDeviceNicknameResponse.getBody().getSuccess()) {
                throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
            }
        }
        Device device = BeanUtil.copyProperties(deviceDto, Device.class);
        return deviceMapper.updateByPrimaryKeySelective(device);
    }

    @Override
    @Transactional
    public int deleteDeviceByConditions(DeviceDto deviceDto) {
        deleteDevice(deviceDto);
        return deviceMapper.deleteByIotIdAndProductKey(deviceDto.getIotId(), deviceDto.getProductKey());
    }

    @Override
    public QueryDevicePropertyStatusResponseBody.QueryDevicePropertyStatusResponseBodyData queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        if (response == null || !response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return response.getBody().getData();
    }

    @Override
    public QueryThingModelPublishedResponseBody.QueryThingModelPublishedResponseBodyData queryThingModelPublished(QueryThingModelPublishedRequest request) {
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        if (response == null || !response.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        return response.getBody().getData();
    }

    @NotNull
    private static List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> getBatchUpdateDeviceNicknameRequestDeviceNicknameInfos(DeviceDto deviceDto) {
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> list = new ArrayList<>();
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo deviceNicknameInfo = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        deviceNicknameInfo.setIotId(deviceDto.getIotId());
        deviceNicknameInfo.setNickname(deviceDto.getNickname());
        deviceNicknameInfo.setProductKey(deviceDto.getProductKey());
        list.add(deviceNicknameInfo);
        return list;
    }


    private void deleteDevice(DeviceDto deviceDto) {
        DeleteDeviceRequest deleteRequest = new DeleteDeviceRequest();
        deleteRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        deleteRequest.setProductKey(deviceDto.getProductKey());
        deleteRequest.setDeviceName(deviceDto.getDeviceName());
        deleteRequest.setIotId(deviceDto.getIotId());
        DeleteDeviceResponse deleteDeviceResponse;
        try {
            deleteDeviceResponse = client.deleteDevice(deleteRequest);
        } catch (Exception ex) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
        if (deleteDeviceResponse == null || !deleteDeviceResponse.getBody().getSuccess()) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }
    }
}
